//
//  ZBJSONKit.m
//  ZBExtensionKit
//
//  Created by apple on 2018/8/10.
//  Copyright © 2018年 apple. All rights reserved.
//

#import "ZBJSONKit.h"
#import "Animal.h"

/**
 *  遍历所有类的block（父类）
 */
typedef void (^ZBClassesEnumeration)(Class cls, BOOL *stop);
static NSSet *foundationClasses_;

@implementation ZBJSONKit
/**
  字典或json格式字符 -- >模型
 */
+(id)zb_objectWithClass:(__unsafe_unretained _Nonnull Class)cls value:(id)value
{
    if(value == nil) return nil;
    NSMutableDictionary* dataDict;
    id object = [cls new];
    //1.判断类型并填充字典数据
    if([value isKindOfClass:[NSString class]]){
        NSAssert([NSJSONSerialization isValidJSONObject:value],@"json数据格式错误!");
        dataDict = [[NSMutableDictionary alloc]initWithDictionary:[self zb_jsonWithString:value] copyItems:YES];
    }else if ([value isKindOfClass:[NSDictionary class]]){
        dataDict = [[NSMutableDictionary alloc] initWithDictionary:value copyItems:YES];
    }else{
        NSAssert(NO,@"数据格式错误!, 只能转换字典或json格式数据.");
    }
    
    //2.判断协议方法时候实现
    
    //2.1 获取数组中
    NSDictionary *const objClsInArr = [ZBJSONKit checkExecuteSelector:NSSelectorFromString(@"zb_configObjectClassInArray") fromClass:[object class]];
    
    //2.2获取替换属性字典
     NSDictionary* const replacedKeyFromPropertyNameDict = [ZBJSONKit checkExecuteSelector:NSSelectorFromString(@"zb_configReplacedKeyFromPropertyName") fromClass:[object class]];
    

    //2.3自定义类型字典
    NSDictionary* const objectClaForCustom = [ZBJSONKit checkExecuteSelector:NSSelectorFromString(@"zb_configObjectClassForCustom") fromClass:[object class]];
    
    //2.3获取当前类的属性数组
    NSArray* const clsKeys = [self getClassIvarList:cls onlyKey:YES];
    
    //3.遍历自定义变量集合信息.
    !objectClaForCustom?:[objectClaForCustom enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull customKey, id  _Nonnull customObj, BOOL * _Nonnull stop) {
        if ([customKey containsString:@"."]){
            NSArray* keyPaths = [customKey componentsSeparatedByString:@"."];
            id value = [dataDict valueForKeyPath:customKey];
            dataDict[keyPaths.lastObject] = value;
            if(![objectClaForCustom.allKeys containsObject:keyPaths.firstObject]){
                [dataDict removeObjectForKey:keyPaths.firstObject];
            }
        }
    }];
    
    
    
    //4.处理要替换的key和属性名.
    if(replacedKeyFromPropertyNameDict && replacedKeyFromPropertyNameDict.count)
    {
        [replacedKeyFromPropertyNameDict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            if([dataDict.allKeys containsObject:key]){
                dataDict[obj] = dataDict[key];
                [dataDict removeObjectForKey:key];
            }
        }];
    }
    
    //4.处理字典 -- > model
    [dataDict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull dataDictObj, BOOL * _Nonnull stop) {
        for(NSString* claKey in clsKeys){
            if ([key isEqualToString:claKey]){
                __block id ArrObject = dataDictObj;
                //遍历自定义变量数组集合信息.
                !objClsInArr?:[objClsInArr enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull Arrkey, id  _Nonnull ArrObjCla, BOOL * _Nonnull stop){
                    if([key isEqualToString:Arrkey]){
                        NSMutableArray* ArrObjects = [NSMutableArray array];
                        for(NSDictionary* ArrObj in dataDictObj){
                            id obj = [self zb_objectWithClass:ArrObjCla value:ArrObj];
                            [ArrObjects addObject:obj];
                        }
                        ArrObject = ArrObjects;
                        *stop = YES;
                    }
                }];
                
                //遍历自定义变量集合信息.
                !objectClaForCustom?:[objectClaForCustom enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull customKey, id  _Nonnull customObj, BOOL * _Nonnull stop) {
                    NSString* tempKey = customKey;
                    if ([customKey containsString:@"."]){
                        tempKey = [customKey componentsSeparatedByString:@"."].lastObject;
                    }
                    
                    if([key isEqualToString:tempKey]){
                        ArrObject = [self zb_objectWithClass:customObj value:[dataDict valueForKey:tempKey]];
                        *stop = YES;
                    }
                }];
        
                [object setValue:ArrObject forKey:key];
                break;//匹配到了就跳出循环.
            }
        }
    }];
    
    return object;
}

/**
 模型 -- >字典.
 */
+(NSMutableDictionary*)zb_keyValuesWithObject:(id)object {
    NSMutableArray<NSString*>* keys = [[NSMutableArray alloc] initWithArray:[self getClassIvarList:[object class] onlyKey:YES]];
    
    //忽略的字段
    NSArray *const ignoredKeys = [ZBJSONKit checkExecuteSelector:NSSelectorFromString(@"zb_configIgnoredKeys") fromClass:[object class]];
    
    if (ignoredKeys) {
        [keys removeObjectsInArray:ignoredKeys];
    }
    
    NSDictionary *const objClsInArr = [ZBJSONKit checkExecuteSelector:NSSelectorFromString(@"zb_configObjectClassInArray") fromClass:[object class]];
    
    NSDictionary* const objectClaForCustom = [ZBJSONKit checkExecuteSelector:NSSelectorFromString(@"zb_configDictForCustomClass") fromClass:[object class]];
    
    NSMutableDictionary* dictM = [NSMutableDictionary dictionary];
    
    [keys enumerateObjectsUsingBlock:^(NSString * _Nonnull key, NSUInteger idx, BOOL * _Nonnull stop) {
        __block id value = [object valueForKey:key];
        //遍历自定义变量数组集合信息.
        !objClsInArr?:[objClsInArr enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull Arrkey, id  _Nonnull ArrObjCla, BOOL * _Nonnull stop){
            if([key isEqualToString:Arrkey]){
                NSMutableArray* ArrObjects = [NSMutableArray array];
                for(id arrObj in value){
                    id dictObj = [self zb_keyValuesWithObject:arrObj];
                    [ArrObjects addObject:dictObj];
                }
                value = ArrObjects;
                *stop = YES;
            }
        }];
        //遍历自定义变量集合信息.
        !objectClaForCustom?:[objectClaForCustom enumerateKeysAndObjectsUsingBlock:^(NSString*  _Nonnull customKey, id  _Nonnull customObj, BOOL * _Nonnull stop) {
            if([key isEqualToString:customKey]){
                value = [self zb_keyValuesWithObject:[object valueForKey:customKey]];
                *stop = YES;
            }
        }];
        
        //存到集合里.
        !value?:[dictM setValue:value forKey:key];
    }];
    
    
    return dictM;
}

/**
 json字符 -- >json格式数据 .
 */
+(id)zb_jsonWithString:(NSString*)jsonString
{
    NSAssert(jsonString, @"jsonString数据不能为空！");
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSError *err;
    id dic = [NSJSONSerialization JSONObjectWithData:jsonData
                                             options:NSJSONReadingMutableContainers
                                               error:&err];
    
    NSAssert(!err,@"json解析失败");
    return dic;
}

/**
 字典 -- >json字符 .
 */
+(NSString*)zb_keyValueToJSONString:(id)json{
    NSAssert(json,@"数据不能为空!");
    NSError *parseError = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingPrettyPrinted error:&parseError];
    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}




/**
 根据类获取变量名列表
 @onlyKey YES:紧紧返回key,NO:在key后面添加type  格式是key&type.
 */
+(NSArray*)getClassIvarList:(__unsafe_unretained Class)cla  onlyKey:(BOOL)onlyKey
{
    NSMutableArray* keys = [NSMutableArray array];
    [self zb_enumerateClasses:cla complete:^(__unsafe_unretained Class c, BOOL *stop) {
        unsigned int numIvars; //成员变量个数
        Ivar *vars = class_copyIvarList(c, &numIvars);
        for(int i = 0; i < numIvars; i++) {
            Ivar thisIvar = vars[i];
            NSString* key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];//获取成员变量的名
            if ([key hasPrefix:@"_"]) {
                key = [key substringFromIndex:1];
            }
            if (!onlyKey) {
                //获取成员变量的数据类型
                NSString* type = [NSString stringWithUTF8String:ivar_getTypeEncoding(thisIvar)];
                key = [NSString stringWithFormat:@"%@&%@",key,type];
            }
            [keys addObject:key];//存储对象的变量名
        }
        free(vars);//释放资源
    }];
    return keys;
}

+ (void)zb_enumerateClasses:(__unsafe_unretained Class)srcCls complete:(ZBClassesEnumeration)enumeration
{
    // 1.没有block就直接返回
    if (enumeration == nil) return;
    // 2.停止遍历的标记
    BOOL stop = NO;
    // 3.当前正在遍历的类
    Class c = srcCls;
    // 4.开始遍历每一个类
    while (c && !stop) {
        // 4.1.执行操作
        enumeration(c, &stop);
        // 4.2.获得父类
        c = class_getSuperclass(c);
        if ([self isClassFromFoundation:c]) break;
    }
}

+ (BOOL)isClassFromFoundation:(Class)c
{
    if (c == [NSObject class]) return YES;
    __block BOOL result = NO;
    [[self foundationClasses] enumerateObjectsUsingBlock:^(Class foundationClass, BOOL *stop) {
        if ([c isSubclassOfClass:foundationClass]) {
            result = YES;
            *stop = YES;
        }
    }];
    return result;
}

+ (NSSet *)foundationClasses
{
    if (foundationClasses_ == nil) {
        // 集合中没有NSObject，因为几乎所有的类都是继承自NSObject，具体是不是NSObject需要特殊判断
        foundationClasses_ = [NSSet setWithObjects:
                              [NSURL class],
                              [NSDate class],
                              [NSValue class],
                              [NSData class],
                              [NSError class],
                              [NSArray class],
                              [NSDictionary class],
                              [NSString class],
                              [NSAttributedString class], nil];
    }
    return foundationClasses_;
}
#pragma mark - pravite 判断
/**
 判断类是否实现了某个类方法.
 */
+ (id)checkExecuteSelector:(SEL)seletor fromClass:(Class)cls
{
    id object = nil;
    BOOL check = [cls respondsToSelector:seletor];
    if(check){
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        object = [cls performSelector:seletor];
#pragma clang diagnostic pop
    }
    return object;
}
/**
 判断对象是否实现了某个方法.
 */
+(id)checkExecuteSelector:(SEL)selector fromObject:(id)obj{
    id object = nil;
    BOOL check = [obj respondsToSelector:selector];
    if(check){
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        object = [obj performSelector:selector];
#pragma clang diagnostic pop
    }
    return object;
}

@end
